package com.cenntro.auth.service.impl;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;

import javax.annotation.Resource;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.subject.support.DelegatingSubject;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.cenntro.auth.mapper.SysPermissionMapper;
import com.cenntro.auth.mapper.SysSooidMapper;
import com.cenntro.auth.model.dbo.SysAgentDO;
import com.cenntro.auth.model.dbo.SysPermissionDO;
import com.cenntro.auth.model.dbo.SysSooidDO;
import com.cenntro.auth.model.dbo.SysSooidRoleRefDO;
import com.cenntro.auth.model.vo.SysSooidAddVO;
import com.cenntro.auth.service.SysAgentService;
import com.cenntro.auth.service.SysRoleService;
import com.cenntro.auth.service.SysSooidRoleRefService;
import com.cenntro.auth.service.SysSooidService;
import com.cenntro.auth.shiro.UserRealm;
import com.cenntro.auth.shiro.cache.RedisCacheManager;
import com.cenntro.auth.utils.BeanFill;
import com.cenntro.common.base.BaseServiceImpl;
import com.cenntro.common.redis.IRedisService;
import com.cenntro.common.util.ConvertorUtils;
import com.cenntro.common.util.KeyUtil;
import com.cenntro.common.util.KeyUtil.keyEnum;
import com.cenntro.common.util.MessageDigestUtil;
import com.cenntro.common.util.result.Result;
import com.cenntro.common.websocket.ChannelSupervise;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;

import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * 账号数据表 服务实现类
 * </p>
 *
 * @author 
 * @since 2019-02-15
 */
@Slf4j
@Service("sooidService")
public class SysSooidServiceImpl extends BaseServiceImpl<SysSooidMapper> implements SysSooidService {

    @Autowired
    private IRedisService redisService;

    @Resource
    private SysSooidRoleRefService sysSooidRoleRefService;

    @Resource
    private SysRoleService sysRoleService;

    @Resource
    private SysAgentService sysAgentService;

    @Autowired
    private SysPermissionMapper permissionMapper;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int insert(Object t) {
        SysSooidAddVO sooidVO = (SysSooidAddVO) t;
        SysSooidDO sooidDO = new SysSooidDO();
        sooidDO.setUserName(sooidVO.getUserName());
        int count = super.selectCount(sooidDO);
        if (count == 0) {
            sooidDO = ConvertorUtils.deepConvert(sooidVO, SysSooidDO.class);
            BeanFill.fillByCreate(sooidDO);
            sooidDO.setPassword(MessageDigestUtil.MD5(sooidDO.getPassword()));
            if (sooidVO.getAgentId() != null) {
                SysAgentDO sysAgent = sysAgentService.selectById(sooidVO.getAgentId());
                if (sysAgent != null) {
                    sooidDO.setAgentPath(sysAgent.getAgentPath());
                }
            }
            count = super.insert(sooidDO);
            final int sooid = sooidDO.getId();
            if (StringUtils.isNotBlank(sooidVO.getRoleIds())) {// 没有检查角色是否存在
                String[] ids = sooidVO.getRoleIds().split(",");
                Arrays.stream(ids).forEach(id -> {
                    SysSooidRoleRefDO sysSooidRoleRefDO = new SysSooidRoleRefDO();
                    sysSooidRoleRefDO.setRoleId(NumberUtils.toInt(id));
                    sysSooidRoleRefDO.setSooid(sooid);
                    sysSooidRoleRefDO.setCdt(new Date());
                    sysSooidRoleRefService.insert(sysSooidRoleRefDO);
                });
            }
        } else {
            count = -1;
        }
        return count;
    }

    @Override
    public int updateSysSooid(SysSooidDO sysSooid) {
       return super.update(sysSooid);
    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int update(Object t) {
        SysSooidAddVO sooidVO = (SysSooidAddVO) t;
        SysSooidDO sooidDO = null;
        if (StringUtils.isNotBlank(sooidVO.getUserName())) {
            sooidDO = this.selectOne(ImmutableMap.of("userName", sooidVO.getUserName()));
            if (sooidDO != null) {
                if (!sooidDO.getId().equals(sooidVO.getId())) {
                    return -1;
                }
            }
        }
        sooidDO = ConvertorUtils.deepConvert(sooidVO, SysSooidDO.class);
        if(sooidDO.getPassword() != null){
            sooidDO.setPassword(MessageDigestUtil.MD5(sooidDO.getPassword()));
        }
        if (sooidVO.getAgentId() != null) {
            SysAgentDO sysAgent = sysAgentService.selectById(sooidVO.getAgentId());
            if (sysAgent != null) {
                sooidDO.setAgentPath(sysAgent.getAgentPath());
            }
        }
        BeanFill.fillByUpdate(sooidDO);
        super.update(sooidDO);
        final int sooid = sooidDO.getId();
        String[] user = { sooid + "" };
        sysSooidRoleRefService.deleteByUser(sooid);
        List<String> StringPermissions = Lists.newArrayList();
        if (StringUtils.isNotBlank(sooidVO.getRoleIds())) {
            String[] ids = sooidVO.getRoleIds().split(","); // 没有检查角色是否存在
            Arrays.stream(ids).forEach(id -> {
                SysSooidRoleRefDO sysSooidRoleRefDO = new SysSooidRoleRefDO();
                sysSooidRoleRefDO.setRoleId(NumberUtils.toInt(id));
                sysSooidRoleRefDO.setSooid(sooidVO.getId());
                sysSooidRoleRefDO.setCdt(new Date());
                sysSooidRoleRefService.insert(sysSooidRoleRefDO);
            });
            List<SysPermissionDO> permission = this.selectPermissionByUserId(sooid);
            for (SysPermissionDO perm : permission) {
                StringPermissions.add(perm.getUrl());
            }
        }
        this.reflush(user, sooidDO.getUserName(), null);
        return 1;
    }
    
    public Result verify() {
        return Result.ok();
    }

    /**
     * 查询用户对应的权限
     * @return
     */
    public List<SysPermissionDO> selectPermissionByUserId(Integer userId) {
        List<Integer> roleList = (List<Integer>)redisService.get(KeyUtil.keyOf(keyEnum.SHIRO_ROLES, userId), Object.class);
        List<SysPermissionDO> permList;
        if (CollectionUtils.isEmpty(roleList)) {
            SysSooidRoleRefDO roleRef = new SysSooidRoleRefDO();
            roleRef.setSooid(userId);
            List<SysSooidRoleRefDO> roleRefList = sysSooidRoleRefService.selectPage(roleRef);
            if (CollectionUtils.isNotEmpty(roleRefList)) {
                roleList = Lists.newArrayList();
                for (SysSooidRoleRefDO ref : roleRefList) {
                    roleList.add(ref.getRoleId());
                }
            }
        }
        if (CollectionUtils.isNotEmpty(roleList)) {
            permList = permissionMapper.selectPermByRoleIds(roleList);
        } else {
            permList = Lists.newArrayList();
        }
        return permList;
    }

    @Transactional
    @Override
    public int deleteById(Integer id) {
        // sysSooidRoleRefService.deleteByUser(id);
        SysSooidDO sooid = new SysSooidDO();
        sooid.setStatus(-1);
        sooid.setId(id);
        return super.update(sooid);
    }
    /**
     * 方法1、刷新用户权限，角色
     * @return
     */
    public Result reflush(String[] userId, String StringPermissions, Integer roleType) {
//        SecurityUtils.getSubject().logout();
        // 重新修改权限后清楚缓存，调用doGetAuthorizationInfo重新取角色的权限信息
        // RealmSecurityManager rsm = (RealmSecurityManager)
        // SecurityUtils.getSecurityManager();
        // UserRealm shiroRealm = (UserRealm)rsm.getRealms().iterator().next();
        //
        // Subject subject = SecurityUtils.getSubject();
        // String realmName =
        // subject.getPrincipals().getRealmNames().iterator().next();
        // log.info("reflush userId= {}", userId);
        // //shiroRealm.clearAllCachedAuthorizationInfo2();//清楚所有用户权限
        // //第一个参数为用户名,第二个参数为realmName,test想要操作权限的用户
        // SimplePrincipalCollection principals = new
        // SimplePrincipalCollection(user.getEmail(),realmName);
        // subject.runAs(principals);
        // shiroRealm.getAuthorizationCache().remove(subject.getPrincipals());
        // shiroRealm.getAuthorizationCache().remove(user.getEmail());
        // subject.releaseRunAs();

        // myRealm.getAuthenticationCache().remove(sooid); // cache
        // Subject subject = SecurityUtils.getSubject();
        // subject.getPrincipals().getRealmNames().iterator().next();
        // //第一个参数为用户名,第二个参数为realmName,test想要操作权限的用户
        // SimplePrincipalCollection principals = new
        // SimplePrincipalCollection(username,realmName);
        // subject.runAs(principals);
        // myRealm.getAuthorizationCache().remove(subject.getPrincipals());
        // subject.releaseRunAs();
        
//        UserRealm myRealm = (UserRealm) rsm.getRealms().iterator().next();
//      RedisCacheManager rcm = (RedisCacheManager) myRealm.getCacheManager();
//      RedisCache rc = (RedisCache) rcm.getCache();
        
        //管理修改其他用户以后， 同步修改登录信息
        DefaultWebSecurityManager rsm = (DefaultWebSecurityManager) SecurityUtils.getSecurityManager();
        DefaultWebSessionManager webseesion =  (DefaultWebSessionManager) rsm.getSessionManager();
        List<String> ids = ChannelSupervise.send(userId, StringUtils.join(StringPermissions));
        for (int i=0; i < ids.size(); i ++){
            int userid = NumberUtils.toInt(ids.get(i));
            SysSooidDO  sysSooidDO = this.selectById(userid);
            if(roleType != null){
                sysSooidDO.setRoleType(roleType);
            }
            try{
                Session session = webseesion.getSessionDAO().readSession(sysSooidDO.getToken());
                if(session != null){
                    PrincipalCollection newPrincipalCollection = new SimplePrincipalCollection(sysSooidDO, sysSooidDO.getUserName());
                    List<PrincipalCollection> list = new CopyOnWriteArrayList<>();
                    list.add(0, newPrincipalCollection);
                    session.setAttribute(DelegatingSubject.class.getName() + ".RUN_AS_PRINCIPALS_SESSION_KEY", list);
                    UserRealm shiroRealm = (UserRealm)rsm.getRealms().iterator().next();
//                    org.apache.shiro.cache.Cache c = shiroRealm.getCacheManager().getCache(RedisCacheManager.cacheName);
//                    SysSooidDO sooid = new SysSooidDO();
//                    sooid.setId(userid);
//                    c .remove(sooid);
                    shiroRealm.doClearCache(newPrincipalCollection);
                }
            }catch(Exception e){
                log.info("异常：" , e);
            }
        }
     
      return Result.ok();
    }
}
